#include "app/app_main.h"
#include "debug.h"

static void nx_application_define(VOID *first_unused_memory);

/**********************************************************************************************/
#define DEMO_STACK_SIZE				512
#define DEMO_BYTE_POOL_SIZE 	9120

TX_THREAD thread_0;
TX_THREAD thread_1;

static void thread_0_entry(ULONG thread_input);
static void thread_1_entry(ULONG thread_input);

VOID tx_application_define(VOID *first_unused_memory)
{
	CHAR *pointer = TX_NULL;
	TX_BYTE_POOL byte_pool_0;

	/* Create a byte memory pool from which to allocate the thread stacks.  */
	tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);

	/* Put system definition stuff in here, e.g. thread creates and other assorted
		 create information.  */

	/* Allocate the stack for thread 0.  */
	tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

	/* Create the main thread.  */
	tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,  
					pointer, DEMO_STACK_SIZE, 
					1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);


	/* Allocate the stack for thread 1.  */
	tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

	/* Create threads 1 and 2. These threads pass information through a ThreadX 
		 message queue.  It is also interesting to note that these threads have a time
		 slice.  */
	tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,  
					pointer, DEMO_STACK_SIZE, 
					16, 16, 4, TX_AUTO_START);
	
	app_udp_client_create(&byte_pool_0);
	
	nx_application_define(&byte_pool_0);
}

void thread_0_entry(ULONG thread_input)
{
	/* This thread simply sits in while-forever-sleep loop.  */
	while(1)
	{
		PRINTF("thread 0 is running..\r\n");
		PRINTF("tick:%d\r\n",HAL_GetTick());
		
		tx_thread_sleep(10000);
	}
}

void thread_1_entry(ULONG thread_input)
{
	/* This thread simply sends messages to a queue shared by thread 2.  */
	while(1)
	{
		PRINTF("thread 1 is running..\r\n");
		
		tx_thread_sleep(5000);
	}
}

/**********************************************************************************************/
#include "eth/eth_nx_driver.h"

/* Define the ThreadX and NetX object control blocks...  */

NX_PACKET_POOL    pool_0;
NX_IP             ip_0;  
#ifdef NX_ENABLE_DHCP
NX_DHCP           dhcp_client;
UCHAR             ip_address[4];
UCHAR             network_mask[4];
TX_THREAD         thread_0;
UCHAR             thread_0_stack[2048];
#endif

/* 定义BSD封装层线程的栈大小 */
#define BSD_SOCKET_STACK 2048

/* Define the IP thread's stack area.  */

ULONG             ip_thread_stack[2 * 1024 / sizeof(ULONG)];


/* Define packet pool for the demonstration.  */

#define NX_PACKET_POOL_SIZE ((1536 + sizeof(NX_PACKET)) * 50)

ULONG             packet_pool_area[NX_PACKET_POOL_SIZE/4 + 4];


/* Define the ARP cache area.  */

ULONG             arp_space_area[512 / sizeof(ULONG)];

                                                           
/* Define an error counter.  */

ULONG             error_counter;

#ifdef NX_ENABLE_DHCP
VOID    thread_0_entry(ULONG thread_input);
#endif

void nx_application_define(VOID *first_unused_memory)
{
	UINT  status;
	char *pointer = TX_NULL;
	 
	/* Initialize the NetX system.  */
	nx_system_initialize();

	/* Create a packet pool.  */
	status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1536,  (ULONG*)(((int)packet_pool_area + 15) & ~15) , NX_PACKET_POOL_SIZE);

	/* Check for pool creation error.  */
	if (status)
			error_counter++;

	/* Create an IP instance.  */
	status = nx_ip_create(&ip_0,
												"NetX IP Instance 0",
#ifdef NX_ENABLE_DHCP
												IP_ADDRESS(0,0,0,0),
												IP_ADDRESS(0,0,0,0),
#else
												IP_ADDRESS(192, 168, 0, 217),
												0xFFFFFF00UL,
#endif
												&pool_0, nx_driver_entry,
												(UCHAR*)ip_thread_stack,
												sizeof(ip_thread_stack),
												1);

	/* Check for IP create errors.  */
	if (status)
			error_counter++;
			
	/* Enable ARP and supply ARP cache memory for IP Instance 0.  */
	status =  nx_arp_enable(&ip_0, (void *)arp_space_area, sizeof(arp_space_area));

	/* Check for ARP enable errors.  */
	if (status)
			error_counter++;

	/* Enable TCP traffic.  */
	status =  nx_tcp_enable(&ip_0);

	/* Check for TCP enable errors.  */
	if (status)
			error_counter++;

	/* Enable UDP traffic.  */
	status =  nx_udp_enable(&ip_0);

	/* Check for UDP enable errors.  */
	if (status)
			error_counter++;

	/* Enable ICMP.  */
	status =  nx_icmp_enable(&ip_0);

	/* Check for errors.  */
	if (status)
			error_counter++;

	/* Allocate the stack for thread 1.  */
	tx_byte_allocate(first_unused_memory, (VOID **) &pointer, BSD_SOCKET_STACK, TX_NO_WAIT);
	/* Now initialize BSD Socket Wrapper */
	status = (UINT)bsd_initialize (&ip_0, &pool_0, pointer, BSD_SOCKET_STACK, 2);

	if (status)
			error_counter++;

#ifdef NX_ENABLE_DHCP
	/* Create the main thread.  */
	tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,  
									 thread_0_stack, sizeof(thread_0_stack), 
									 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); 
#endif
}

#ifdef NX_ENABLE_DHCP
/* Define the test threads.  */
void    thread_0_entry(ULONG thread_input)
{
UINT    status;
ULONG   actual_status;
ULONG   temp;


    /* Create the DHCP instance.  */
    printf("\r\nDHCP In Progress...\r\n");

    nx_dhcp_create(&dhcp_client, &ip_0, "dhcp_client");

    /* Start the DHCP Client.  */
    nx_dhcp_start(&dhcp_client);
    
    /* Wait until address is solved. */
    status = nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &actual_status, 1000);
    
    if (status)
    {
        
        /* DHCP Failed...  no IP address! */
        printf("Can't resolve address\r\n");
    }
    else
    {
        
        /* Get IP address. */
        nx_ip_address_get(&ip_0, (ULONG *) &ip_address[0], (ULONG *) &network_mask[0]);

        /* Convert IP address & network mask from little endian.  */
        temp =  *((ULONG *) &ip_address[0]);
        NX_CHANGE_ULONG_ENDIAN(temp);
        *((ULONG *) &ip_address[0]) =  temp;
        
        temp =  *((ULONG *) &network_mask[0]);
        NX_CHANGE_ULONG_ENDIAN(temp);
        *((ULONG *) &network_mask[0]) =  temp;

        /* Output IP address. */
        printf("IP address: %d.%d.%d.%d\r\n",
               (UINT) (ip_address[0]),
               (UINT) (ip_address[1]),
               (UINT) (ip_address[2]),
               (UINT) (ip_address[3]));
        printf("Mask: %d.%d.%d.%d\r\n",
               (UINT) (network_mask[0]),
               (UINT) (network_mask[1]),
               (UINT) (network_mask[2]),
               (UINT) (network_mask[3]));
    }
}
#endif /*NX_ENABLE_DHCP*/
